package com.springmvc.platform.base.interceptor;

import com.springmvc.platform.base.datasource.DataSourceContextHolder;
import com.springmvc.platform.base.datasource.DynamicDataSourceGlobal;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 动态切换数据源插件
 * @create 2017/11/6
 * @modify
 */
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {
                MappedStatement.class, Object.class }),
        @Signature(type = Executor.class, method = "query", args = {
                MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class }) })
public class DynamicDataSourceInterceptor implements Interceptor{
    protected static final Logger _logger = LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);

    private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*";

    private static final Map<String, DynamicDataSourceGlobal> cacheMap = new ConcurrentHashMap<String, DynamicDataSourceGlobal>();

    public Object intercept(Invocation invocation) throws Throwable {
        boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
        Object[] objects = invocation.getArgs();
        MappedStatement ms = (MappedStatement) objects[0];
        DynamicDataSourceGlobal dynamicDataSourceGlobal=cacheMap.get(ms.getId());
        //如果没有记录当前操作的数据源类型对数据源类型进行设置
        if(dynamicDataSourceGlobal == null){
            //读方法
            if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)){
                //应该是采用主键自增插入时会以select开始，所有要排查这种情况为写数据库
                if(ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)){
                    dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;
                }else{
                    BoundSql boundSql = ms.getSqlSource().getBoundSql(objects[1]);
                    String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", " ");
                    if(sql.matches(REGEX)) {
                        dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;
                    } else {
                        dynamicDataSourceGlobal = DynamicDataSourceGlobal.READ;
                    }
                    _logger.warn("设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..", ms.getId(), dynamicDataSourceGlobal.getName(), ms.getSqlCommandType().name());
                    cacheMap.put(ms.getId(), dynamicDataSourceGlobal);
                }
            }else{
                //写方法
                dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;
            }
        }
        //设置动态切换数据库
        DataSourceContextHolder.setDataSource(dynamicDataSourceGlobal.getName());
        return invocation.proceed();
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {

    }
}
